package com.webinsky.web.resource;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;

import com.webinsky.article.domain.MisArticle;
import com.webinsky.article.service.ArticleManagement;
import com.webinsky.common.proj.BookMode;
import com.webinsky.common.proj.Lang;
import com.webinsky.domain.catalog.Catalogs;
import com.webinsky.domain.resource.Resource;
import com.webinsky.domain.user.Account;
import com.webinsky.folder.domain.FolderArticle;
import com.webinsky.folder.domain.FolderIndex;
import com.webinsky.folder.domain.FolderType;
import com.webinsky.folder.service.FolderManagement;
import com.webinsky.publish.domain.MisVersion;
import com.webinsky.publish.service.BookPublishManagement;
import com.webinsky.service.catalog.CatalogManagement;
import com.webinsky.service.catalog.TagManagement;
import com.webinsky.service.resource.ResManagement;
import com.webinsky.service.user.AuthorizationManagement;
import com.webinsky.service.user.UserManagement;
import com.webinsky.web.data.Response;
import com.webinsky.web.data.VersionForm;

import reactor.core.publisher.Mono;

@Component
public class StaticResource {
	@Autowired
	private BookPublishManagement bookPublishManagement;
	@Autowired
	private FolderManagement folderManagement;
	@Autowired
	private ArticleManagement articleManagement;
	@Autowired
	private CatalogManagement catalogManagement;
	@Autowired
	private TagManagement tagManagement;
	@Autowired
	private AuthorizationManagement authorizationManagement;
	@Autowired
	private ResManagement resManagement;
	@Autowired
	private UserManagement userManagement;
	@Value("${publish.path}")
	private String BASE_PATH;
	@Value("${resource.upload.path}")
	private String BASE_PATH_2;

	/*****************************************************************************
	 * 
	 *  私有方法
	 * 
	 */
	
	private static class BookArticle {
		private int folderId;
		private String siteId;
		private String language;
		private String type;
		private String folderName;
		private List<Article> articles;
		
		public int getFolderId() {
			return folderId;
		}
		public void setFolderId(int folderId) {
			this.folderId = folderId;
		}
		public String getSiteId() {
			return siteId;
		}
		public void setSiteId(String siteId) {
			this.siteId = siteId;
		}
		public String getLanguage() {
			return language;
		}
		public void setLanguage(String language) {
			this.language = language;
		}
		public String getType() {
			return type;
		}
		public void setType(String type) {
			this.type = type;
		}
		public String getFolderName() {
			return folderName;
		}
		public void setFolderName(String folderName) {
			this.folderName = folderName;
		}
		public List<Article> getArticles() {
			return articles;
		}
		public void setArticles(List<Article> articles) {
			this.articles = articles;
		}
	}
	
	private static class Article {
		private int id;
		private String type;
		private int folderId;
		private int articleId;
		private String articleTile;
		private String articleNo;
		private int sort;
		private int siteId;
		private String lang;
		private List<String> tags;
		
		public int getId() {
			return id;
		}
		public void setId(int id) {
			this.id = id;
		}
		public String getType() {
			return type;
		}
		public void setType(String type) {
			this.type = type;
		}
		public int getFolderId() {
			return folderId;
		}
		public void setFolderId(int folderId) {
			this.folderId = folderId;
		}
		public int getArticleId() {
			return articleId;
		}
		public void setArticleId(int articleId) {
			this.articleId = articleId;
		}
		public String getArticleTile() {
			return articleTile;
		}
		public void setArticleTile(String articleTile) {
			this.articleTile = articleTile;
		}
		public String getArticleNo() {
			return articleNo;
		}
		public void setArticleNo(String articleNo) {
			this.articleNo = articleNo;
		}
		public int getSort() {
			return sort;
		}
		public void setSort(int sort) {
			this.sort = sort;
		}
		public int getSiteId() {
			return siteId;
		}
		public void setSiteId(int siteId) {
			this.siteId = siteId;
		}
		public String getLang() {
			return lang;
		}
		public void setLang(String lang) {
			this.lang = lang;
		}
		public List<String> getTags() {
			return tags;
		}
		public void setTags(List<String> tags) {
			this.tags = tags;
		}
	}
	
	private static class BookCategory {
		
	}
	
	private Article convert(FolderArticle fa, int siteId, String lang){
		Article article = new Article();
		article.setArticleId(fa.getArticleId());
		article.setArticleNo(fa.getArticleNo());
		article.setArticleTile(fa.getArticleTile());
		article.setSiteId(siteId);
		article.setFolderId(fa.getFolderId());
		article.setId(fa.getId());
		article.setLang(lang);
		article.setType(fa.getType().name());
		article.setSort(fa.getSort());
		List<String> tags = new ArrayList<>();
		if ( fa.getTags() != null && !fa.getTags().isEmpty() ){
			fa.getTags().forEach(t -> tags.add(t));
		}
		article.setTags(tags);
		return article;
	}
	
	private BookArticle convert(FolderIndex index, int siteId, String lang){
		BookArticle ba = new BookArticle();
		ba.setSiteId(String.valueOf(index.getSiteId()));
		ba.setFolderId(index.getFolderId());
		ba.setFolderName(index.getFolderName());
		ba.setLanguage(index.getLanguage().getLang());
		ba.setType(index.getType().name());
		List<Article> articles = new ArrayList<>();
		if ( index.getArticles() != null && !index.getArticles().isEmpty() ){
			index.getArticles().forEach(e -> articles.add(convert(e, siteId, lang)));
		}
		ba.setArticles(articles);
		return ba;
	}
	
	/**
	 * 取得某本书下面的文章
	 * 
	 * @param bookId
	 * @param lang
	 * @return
	 */
	private List<BookArticle> getFolderIndex(int siteId, Lang lang, boolean inOrOut){
		List<BookArticle> bookArticles = new ArrayList<>();
		List<FolderIndex> list = folderManagement.getFolderIndex(siteId, lang);
		// 取得文章内容
		if ( !list.isEmpty() ){
			List<FolderArticle> articles = new ArrayList<>();
			list.forEach(e -> {
				if ( e.getArticles() != null ){
					articles.addAll(e.getArticles());
				}
			});
			// 因为文章信息属于article service,所以要在wrapper service层查到所有信息
			List<Integer> articlesIds = articles.stream().map(e -> e.getArticleId()).collect(Collectors.toList());
			List<Integer> distinctIds = articlesIds.stream().distinct().collect(Collectors.toList());
			List<MisArticle> misArticles = articleManagement.getArticles(distinctIds, true);
			// 文章的mapping关系
			Map<Integer, MisArticle> misArticlesMap = misArticles.stream().collect(Collectors.toMap(MisArticle::getId, Function.identity()));
			list.forEach(l -> {
				if ( l.getArticles() != null ) {
					l.getArticles().forEach(a -> {
						if ( misArticlesMap.get(a.getArticleId()) != null ) {
							a.setArticleTile(misArticlesMap.get(a.getArticleId()).getTitle());
							a.setArticleNo(misArticlesMap.get(a.getArticleId()).getArticleNo());
							if ( misArticlesMap.get(a.getArticleId()).getTags() != null && !misArticlesMap.get(a.getArticleId()).getTags().isEmpty() ) {
								misArticlesMap.get(a.getArticleId()).getTags().forEach(e -> a.getTags().add(String.valueOf(e.getTagId())));
							}
						}
					});
				}
			});
			// 转换
			list.forEach(e -> {
				if ( !inOrOut ){
					// 跳过内部参考
					if ( e.getType() == FolderType.Item && e.getFolderName().equals("内部参考")){
						return;
					}
				}
				bookArticles.add(convert(e, siteId, lang.getLang()));
			});
			
		}
		return bookArticles;
	}
	
	/**
	 * 取得目录
	 * @param bookId
	 * @param lang
	 * @return
	 */
	private Catalogs getBookCategory(int siteId, Lang lang){
		return catalogManagement.getCatalogByPagnation(siteId, lang, 0, 9999);
	}
	
	private void setRelateVideoName(MisArticle article){
		List<Integer> videoIds = new ArrayList<>();
		if ( article.getRelatedVideo() != null ){
			List<Integer> vIds = article.getRelatedVideo().stream().map(v -> v.getRelateVideoId()).collect(Collectors.toList());
			videoIds.addAll(vIds);
		}
		if ( !videoIds.isEmpty() ){
			List<Resource> videoRes = resManagement.getVideoResourceByIds(videoIds);
			if ( !videoRes.isEmpty() ){
				Map<String,Resource> videoResMap = videoRes.stream().collect(Collectors.toMap(Resource::getUid, Function.identity()));
				if ( article.getRelatedVideo() != null ){
					article.getRelatedVideo().forEach(v -> {
						String strId = String.valueOf(v.getRelateVideoId());
						if ( videoResMap.get(strId) != null ){
							v.setVideoName(videoResMap.get(strId).getName());
							v.setVideoFileName(videoResMap.get(strId).getFileName());
						}
					});
				}
			}
		}
	}
	
	private void setVideoName(MisArticle article){
		List<Integer> videoIds = new ArrayList<>();
		if ( article.getArticleVideo() != null ){
			List<Integer> vIds = article.getArticleVideo().stream().map(v -> v.getVideoId()).collect(Collectors.toList());
			videoIds.addAll(vIds);
		}
		if ( !videoIds.isEmpty() ){
			List<Resource> videoRes = resManagement.getVideoResourceByIds(videoIds);
			if ( !videoRes.isEmpty() ){
				Map<String,Resource> videoResMap = videoRes.stream().collect(Collectors.toMap(Resource::getUid, Function.identity()));
				if ( article.getArticleVideo() != null ){
					article.getArticleVideo().forEach(v -> {
						String strId = String.valueOf(v.getVideoId());
						if ( videoResMap.get(strId) != null ){
							v.setVideoUrl(videoResMap.get(strId).getName());
							v.setVideoName(videoResMap.get(strId).getName());
							v.setVideoFileName(videoResMap.get(strId).getFileName());
						}
					});
				}
			}
		}
	}
	
	private MisArticle getArtileDetail(int id){
		MisArticle misArticle = articleManagement.getArticle(id, true);
		if ( misArticle != null ){
			Account account = authorizationManagement.getByUserId(misArticle.getUserId());
			misArticle.setCreator(account.getLoginName());
			// 取得relate video
			setRelateVideoName(misArticle);
			setVideoName(misArticle);
			// 取得tag信息
		}
		return misArticle;
	}
	
	
	/*****************************************************************************
	 * 
	 *  接口定义
	 * 
	 */
	
	/**
	 * 当前版本
	 */
	public Mono<ServerResponse> currentVersion(ServerRequest request){
		return request.session().zipWith(request.bodyToMono(VersionForm.class)).flatMap(data -> {
			List<MisVersion> list = new LinkedList<>();

			MisVersion mold = new MisVersion();
			mold.setId(1);
			mold.setBookMode(BookMode.Mold);
			mold.setVersionName("S20180607-1"); // S + 日期 + 当天第几次发布
			mold.setVersionDate("2018/08/15");
			mold.setAuthor("admin");
			list.add(mold);

			MisVersion press = new MisVersion();
			press.setId(1);
			press.setBookMode(BookMode.Press);
			press.setVersionName("C20180607-1"); // C + 日期 + 当天第几次发布
			press.setVersionDate("2018/08/15");
			press.setAuthor("admin");
			list.add(press);

			return ServerResponse.ok().syncBody(Response.create(list, Response.STATUS_OK, ""));
		});
	}

	/**
	 * 历史版本
	 */
	public Mono<ServerResponse> historyVersion(ServerRequest request){
		return request.session().zipWith(request.bodyToMono(VersionForm.class)).flatMap(data -> {
			List<MisVersion> list = new LinkedList<>();
			List<MisVersion> versions = bookPublishManagement.getVersion(BookMode.parse(data.getT2().bookMode), Lang.parse(data.getT2().lang));
			versions.forEach(e -> {
				if (e.getAuthorId() > 0) {
					Account account = userManagement.getAccountById(e.getAuthorId());
					e.setAuthor(account.getUserName());
				}
				list.add(e);
			});
			return ServerResponse.ok().syncBody(Response.create(list, Response.STATUS_OK, ""));
		});
	}

	/**
	 *  TODO : 发布最新版本
	 */
//	public Mono<ServerResponse> publish(ServerRequest request){
//		return request.session().zipWith(request.bodyToMono(PublishForm.class)).flatMap(data -> {
//			PublishForm publishForm = data.getT2();
//			WebSession session = data.getT1();
//
//			try {
//				// 清理上一次发布的文件
//				// 需要先清空上一次发布用的文件，比如html、图片和视频
//				{
//					File output = new File(BASE_PATH, "Manual");
//					if (output.exists()) {
//						FileUtils.delFolder(output.getAbsolutePath());
//					}
//					File outputStructure = new File(BASE_PATH, "output_structure");
//					if (outputStructure.exists()) {
//						if (!output.exists()) {
//							output.mkdirs();
//						}
//						FileUtils.copyDir(outputStructure.getAbsolutePath(), output.getAbsolutePath());
//					}
//				}
//
//				String[] langArray = {"zhCN", "jaJP", "enUS", "zhTW", "ko", "th"};
//
//				for (String lang : langArray) {
//					// 静态化
//					StaticConfiguration cfg = new StaticConfiguration(BASE_PATH);
//					String bookMode = "Unknown";
////					String lang = "Unknown";
//					String articleDir = "Unknown";
//					String materialDir = "Unknown";
//					switch (Lang.parse(lang)) {
//						case zhCN:
//							switch (BookMode.parse(publishForm.bookMode)) {
//								case Mold:
//									bookMode = "Mold";
//									break;
//								case Press:
//									bookMode = "Press";
//									break;
//							}
////							lang = "zhCN";
//							articleDir = "Article";
//							materialDir = "Material";
//							break;
//						case jaJP:
//							switch (BookMode.parse(publishForm.bookMode)) {
//								case Mold:
//									bookMode = "Mold";
//									break;
//								case Press:
//									bookMode = "Press";
//									break;
//							}
////							lang = "jaJP";
//							articleDir = "Article";
//							materialDir = "Material";
//							break;
//						case enUS:
//							switch (BookMode.parse(publishForm.bookMode)) {
//								case Mold:
//									bookMode = "Mold";
//									break;
//								case Press:
//									bookMode = "Press";
//									break;
//							}
////							lang = "enUS";
//							articleDir = "Article";
//							materialDir = "Material";
//							break;
//						case zhTW:
//							switch (BookMode.parse(publishForm.bookMode)) {
//								case Mold:
//									bookMode = "Mold";
//									break;
//								case Press:
//									bookMode = "Press";
//									break;
//							}
////							lang = "enUS";
//							articleDir = "Article";
//							materialDir = "Material";
//							break;
//						case ko:
//							switch (BookMode.parse(publishForm.bookMode)) {
//								case Mold:
//									bookMode = "Mold";
//									break;
//								case Press:
//									bookMode = "Press";
//									break;
//							}
////							lang = "enUS";
//							articleDir = "Article";
//							materialDir = "Material";
//							break;
//						case th:
//							switch (BookMode.parse(publishForm.bookMode)) {
//								case Mold:
//									bookMode = "Mold";
//									break;
//								case Press:
//									bookMode = "Press";
//									break;
//							}
////							lang = "enUS";
//							articleDir = "Article";
//							materialDir = "Material";
//							break;
//					}
//
//
//					/**
//					 * 首页
//					 */
//					StaticIndexModel model = new StaticIndexModel();
//					model.setBookMode(publishForm.bookMode);
//					model.setLang(lang);
//					StaticIndexFreemarker indexFreemarker = new StaticIndexFreemarker(cfg.get());
//					indexFreemarker.setModel(model);
//					indexFreemarker.outputFile(
//							cfg.getOutputDirectory().getAbsolutePath(),
//							"top.html"
//					);
//
//
//					/**
//					 * 文章检索
//					 */
//					StaticSearchModel searchModel = new StaticSearchModel();
//					searchModel.setBookMode(publishForm.bookMode);
//					searchModel.setLang(lang);
//					searchModel.setArticleDir(articleDir);
//					searchModel.setMaterialDir(materialDir);
//					int bookId = publishForm.s;
//					Lang language = Lang.parse(lang);
//					boolean inOrOut = "true".equals(publishForm.inside);
//					List<BookArticle> bas = getFolderIndex(bookId, language, inOrOut);
//					// 分类列表 /api/folder/list
//					FolderFilter filter = new FolderFilter();
//					filter.setBookId(BookMode.parse(publishForm.bookMode).getId());
//					filter.setLanguage(Lang.parse(lang).getLang());
//					filter.setStart(0);
//					filter.setSize(9999);
//					Folders folders = folderManagement.getFoldersByFilter(filter);
//					if ( !inOrOut ){
//						if ( folders.getTotalSize() > 0 ){
//							folders.setFolders(folders.getFolders().stream().filter( f -> {
//								if ( f.getType() == FolderType.Item && f.getName().equals("内部参考") ){
//									return false;
//								}
//								return true;
//							}).collect(Collectors.toList()));
//							folders.setTotalSize(folders.getFolders().size());
//						}
//					}
//					searchModel.setFolderListJsonString(JsonUtils.toStr(folders));
//					// 所有文章列表 /api/folder/articles
//					searchModel.setArticleListJsonString(JsonUtils.toStr(bas));
//					// 标签分类列表 /api/tag/category/search
//					Catalogs catalogs = getBookCategory(bookId, language);
//					if ( catalogs != null && catalogs.getTotalSize() > 0 ){
//						searchModel.setTagCategoryJsonString(JsonUtils.toStr(catalogs));
//					}
//					// 标签列表 /api/tag/search
//					Tags tags = tagManagement.getTagsByName(-1, null, bookId, language, 0, 9999);
//					if ( tags != null ){
//						searchModel.setTagListJsonString(JsonUtils.toStr(tags));
//					}
//
//					// 保存到文件
//					StaticSearchFreemarker searchFreemarker = new StaticSearchFreemarker(cfg.get());
//					searchFreemarker.setModel(searchModel);
//					searchFreemarker.outputFile(
//							cfg.getOutputDirectory().getAbsolutePath(),
//							bookMode,
//							lang,
//							"search.html"
//					);
//
//					StaticHistoryFreemarker historyFreemarker = new StaticHistoryFreemarker(cfg.get());
//					historyFreemarker.setModel(searchModel);
//					historyFreemarker.outputFile(
//							cfg.getOutputDirectory().getAbsolutePath(),
//							bookMode,
//							lang,
//							"history.html"
//					);
//
//					StaticHotFreemarker hotFreemarker = new StaticHotFreemarker(cfg.get());
//					hotFreemarker.setModel(searchModel);
//					hotFreemarker.outputFile(
//							cfg.getOutputDirectory().getAbsolutePath(),
//							bookMode,
//							lang,
//							"hot.html"
//					);
//
//
//					// TODO 需要返回视频的文件名称和视频名称
//
//
//					/**
//					 * 文章
//					 */
//					for ( BookArticle ba : bas ){
//						for ( Article art : ba.getArticles() ){
//							StaticArticleModel articleModel = new StaticArticleModel();
//							articleModel.setBookMode(bookMode);
//							articleModel.setLang(lang);
//							articleModel.setArticleDir(articleDir);
//							articleModel.setMaterialDir(materialDir);
//							// 文章内容 /api/article
//							MisArticle misArticle = articleManagement.getArticle(art.getArticleId(), true);
//							if ( misArticle != null ){
//								setRelateVideoName(misArticle);
//								setVideoName(misArticle);
//								articleModel.setArticleJsonString(JsonUtils.toStr(misArticle));
//							}
//							articleModel.setFolderListJsonString(JsonUtils.toStr(folders));
//							// 所有文章列表 /api/folder/articles
//							articleModel.setArticleListJsonString(JsonUtils.toStr(bas));
//							// 标签分类列表 /api/tag/category/search
//							if ( catalogs != null && catalogs.getTotalSize() > 0 ){
//								articleModel.setTagCategoryJsonString(JsonUtils.toStr(catalogs));
//							}
//							// 标签列表 /api/tag/search
//							if ( tags != null ){
//								articleModel.setTagListJsonString(JsonUtils.toStr(tags));
//							}
//							// 保存到文件
//							StaticArticleFreemarker articleFreemarker = new StaticArticleFreemarker(cfg.get());
//							articleFreemarker.setModel(articleModel);
//							articleFreemarker.outputFile(
//									cfg.getOutputDirectory().getAbsolutePath(),
//									bookMode,
//									lang,
//									articleDir,
//									art.getArticleNo().substring(0, 1).toUpperCase(),
//									art.getArticleNo().toUpperCase() + ".html"
//							);
//						}
//					}
//
//					// TODO 复制需要的图片和视频文件到 resource/images 和 resource/videos
//
//					String material = BASE_PATH_2.concat("/misumires")
//							.concat("/" + publishForm.bookMode.toLowerCase())
//							.concat("/" + lang)
//							.concat("/material")
//							;
//					File materialFile = new File(material);
//					if (materialFile.exists()) {
//						StringBuilder path = new StringBuilder();
//						path.append(BASE_PATH + "/Manual");
//						switch (BookMode.parse(publishForm.bookMode)) {
//							case Mold:
//								path.append("/Mold");
//								break;
//							case Press:
//								path.append("/Press");
//								break;
//						}
//						switch (Lang.parse(lang)) {
//							case zhCN:
//								path.append("/zhCN");
//								break;
//							case jaJP:
//								path.append("/jaJP");
//								break;
//							case enUS:
//								path.append("/enUS");
//								break;
//							case zhTW:
//								path.append("/zhTW");
//								break;
//							case ko:
//								path.append("/ko");
//								break;
//							case th:
//								path.append("/th");
//								break;
//						}
//						path.append("/Material");
//						File newPath = new File(path.toString());
//						FileUtils.copyDir(materialFile.getAbsolutePath(), newPath.getAbsolutePath());
//					}
//				}
//
//
//				// TODO zip打包
//				// 需要将静态化内容打包成zip存储
//				// zip包的名字是版本名称 S20180607-1.zip // S + 日期 + 当天第几次发布 + .zip
//
//				StringBuilder zipName = new StringBuilder();
//				switch (BookMode.parse(publishForm.bookMode)) {
//					case Mold:
//						zipName.append("M");
//						break;
//					case Press:
//						zipName.append("P");
//						break;
//				}
//				zipName.append("-");
//				Date d = new Date();
//				java.text.DateFormat dateInstance = new java.text.SimpleDateFormat("yyyyMMdd-hhmmss");
//				zipName.append(dateInstance.format(d));
//				if ("true".equals(publishForm.inside)) {
//					zipName.append("-inside");
//				}
//				zipName.append(".zip");
//				File dest = new File(BASE_PATH + "/archives", zipName.toString());
//				File source = new File(BASE_PATH, "Manual");
//				ZipUtils zUtils = new ZipUtils(dest.getAbsolutePath(), source.getAbsolutePath());
//				zUtils.zip();
//
//				for (String lang : langArray) {
//					// 保存历史记录到数据库
//					MisVersion version = new MisVersion();
//					version.setBookMode(BookMode.parse(publishForm.bookMode));
//					version.setLanguage(lang);
//					version.setVersionDate(dateInstance.format(d));
//					version.setVersionName(zipName.toString().replace(".zip", ""));
//					version.setFileName(zipName.toString());
//					Account login = WebSessionUtils.getAccount(session);
//					// Account account = userManagement.getAccountByLoginName(login.getLoginName());
//					if (login != null) {
//						version.setAuthorId(login.getId());
//						version.setAuthor(login.getUserName());
//					}
//					bookPublishManagement.publishVersion(version);
//				}
//
//			} catch (IOException e) {
//				e.printStackTrace();
//			} catch (TemplateException e) {
//				e.printStackTrace();
//			} catch (Exception e) {
//				e.printStackTrace();
//			}
//
//			return ServerResponse.ok().syncBody(Response.create("", Response.STATUS_OK, ""));
//		});
//	}

}
